package com.nutquest.client;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Vector;

import javax.imageio.ImageIO;
import javax.swing.JPanel;

import com.nutquest.common.dataobjects.*;
import com.nutquest.common.dataobjects.Player.PlayerState;
import com.nutquest.common.mapdata.*;

/**
 * This class will render Terrain, Player, and Nut dataobjects to the screen.
 * 
 * <p>
 * In addition to passing in the intial game state via the constructor, it has
 * two main methods for updating the panel:
 * <ul>
 * <li>updateOrAddPlayer</li>
 * <li>updateTerrain</li>
 * </ul> 
 * 
 * </p>
 * 
 * @author Paul and Cobus
 */
public class ForagingMap extends JPanel{

	private static final long serialVersionUID = 1L;

	// this is the max image width and height
	public static final int TILE_DIM = 20;

	// this is how many tiles that this map will be
	public static final int MAP_WIDTH = 21;

	public static final int MAP_HEIGHT = 21;

	private BufferedImage imgGrass, imgTree, imgCat, imgWalnut, imgWater,
			imgtree_core_core, imgtree_core_top_left, imgtree_core_top_right,
			imgtree_core_bot_left, imgtree_core_bot_right,
			imgtree_core_mid_bot, imgtree_core_mid_top, imgtree_core_mid_left,
			imgtree_core_mid_right, imgtree_root_top_tip, imgtree_root_top_mid,
			imgtree_root_top_base;

	private IMapData mapData;
	private Vector<Player> players; // using a vector because this list can grow

	// or shrink.

	/**
	 * Constructor. This will load the Terrain objects and the initial Players.
	 * 
	 * @param mapData
	 *            An array of Terrain objects that make up the current level.
	 * @param players
	 *            An array of Players that we will start off with.
	 */
	public ForagingMap(IMapData mapData, Vector<Player> players) {
		this.mapData = mapData;
		this.players = players;
		
		// Load images
		try {
			imgGrass = ImageIO.read(getClass().getResource(
					"/media/images/terrain_grass.png"));
			imgTree = ImageIO.read(getClass().getResource(
					"/media/images/terrain_tree.png"));
			imgCat = ImageIO.read(getClass().getResource(
					"/media/images/imgCat.png"));
			imgWalnut = ImageIO.read(getClass().getResource(
					"/media/images/nut_walnut.png"));
			imgWater = ImageIO.read(getClass().getResource(
					"/media/images/terrain_water.png"));

			// tree core images
			imgtree_core_bot_left = ImageIO.read(getClass().getResource(
					"/media/images/Tree/Core/tree_core_bot_left.png"));
			imgtree_core_bot_right = ImageIO.read(getClass().getResource(
					"/media/images/Tree/Core/tree_core_bot_right.png"));
			imgtree_core_core = ImageIO.read(getClass().getResource(
					"/media/images/Tree/Core/tree_core_core.png"));
			imgtree_core_mid_bot = ImageIO.read(getClass().getResource(
					"/media/images/Tree/Core/tree_core_mid_bot.png"));
			imgtree_core_mid_left = ImageIO.read(getClass().getResource(
					"/media/images/Tree/Core/tree_core_mid_left.png"));
			imgtree_core_mid_right = ImageIO.read(getClass().getResource(
					"/media/images/Tree/Core/tree_core_mid_right.png"));
			imgtree_core_mid_top = ImageIO.read(getClass().getResource(
					"/media/images/Tree/Core/tree_core_mid_top.png"));
			imgtree_core_top_left = ImageIO.read(getClass().getResource(
					"/media/images/Tree/Core/tree_core_top_left.png"));
			imgtree_core_top_right = ImageIO.read(getClass().getResource(
					"/media/images/Tree/Core/tree_core_top_right.png"));

			// tree root images
			imgtree_root_top_tip = ImageIO.read(getClass().getResource(
					"/media/images/Tree/Root/Top/tree_root_top_tip.png"));
			imgtree_root_top_mid = ImageIO.read(getClass().getResource(
					"/media/images/Tree/Root/Top/tree_root_mid_top.png"));
			imgtree_root_top_base = ImageIO.read(getClass().getResource(
					"/media/images/Tree/Root/Top/tree_root_top_base.png"));

		} catch (IOException ex) {
			System.out.println("Could not load image: " + ex.getMessage());
		}
		setVisible(true);
	}

	/**
	 * This method will repaint the graphics on the panel to reflect the Player
	 * and Terrain dataobjects that we have.
	 */
	@Override
	public void paint(Graphics g) {

		super.paint(g);

		if (mapData != null) {
			Terrain [] theMapData = mapData.getMapData();
			for (int i = 0; i < theMapData.length; i++) {
				Terrain terr = theMapData[i];

				// Make sure that there is Terrain Data to render.
				if (terr != null) {
					BufferedImage buffImg = null;

					// Check to see what type of data there is, and what image
					// we should use.
					if (terr.getType() == Terrain.TerrainType.GRASS) {
						buffImg = imgGrass;
					} else if (terr.getType() == Terrain.TerrainType.TREE) {
						buffImg = imgTree;
					} else if (terr.getType() == Terrain.TerrainType.WATER) {
						buffImg = imgWater;
					} else if (terr.getType() == Terrain.TerrainType.TREE_CORE_CORE) {
						buffImg = imgtree_core_core;
					} else if (terr.getType() == Terrain.TerrainType.TREE_CORE_BOT_RIGHT) {
						buffImg = imgtree_core_bot_right;
					} else if (terr.getType() == Terrain.TerrainType.TREE_CORE_BOT_LEFT) {
						buffImg = imgtree_core_bot_left;
					} else if (terr.getType() == Terrain.TerrainType.TREE_CORE_MID_BOT) {
						buffImg = imgtree_core_mid_bot;
					} else if (terr.getType() == Terrain.TerrainType.TREE_CORE_MID_LEFT) {
						buffImg = imgtree_core_mid_left;
					} else if (terr.getType() == Terrain.TerrainType.TREE_CORE_MID_RIGHT) {
						buffImg = imgtree_core_mid_right;
					} else if (terr.getType() == Terrain.TerrainType.TREE_CORE_MID_TOP) {
						buffImg = imgtree_core_mid_top;
					} else if (terr.getType() == Terrain.TerrainType.TREE_CORE_TOP_LEFT) {
						buffImg = imgtree_core_top_left;
					} else if (terr.getType() == Terrain.TerrainType.TREE_CORE_TOP_RIGHT) {
						buffImg = imgtree_core_top_right;
					} else if (terr.getType() == Terrain.TerrainType.TREE_ROOT_TOP_TIP) {
						buffImg = imgtree_root_top_tip;
					} else if (terr.getType() == Terrain.TerrainType.TREE_ROOT_TOP_MID) {
						buffImg = imgtree_root_top_mid;
					} else if (terr.getType() == Terrain.TerrainType.TREE_ROOT_TOP_BASE) {
						buffImg = imgtree_root_top_base;
					}

					// draw the tile
					g.drawImage(buffImg, terr.getX() * TILE_DIM, terr.getY()
							* TILE_DIM, null);

					// check to see if has nuts, if so, then draw the image.
					ArrayList<Object> objs = terr.getObjects();
					
					if(objs != null)
					{
						if (objs.size() > 0) {
							// draw the contents
							g.drawImage(imgWalnut, terr.getX() * TILE_DIM,
									terr.getY() * TILE_DIM, null);
						}
					}
					

				}

			}

		}

		// Check to see if there are any players to render to the screen.
		if (players != null) {
			// Graphics2D g2D = (Graphics2D) g;
			for (int y = 0; y < players.size(); y++) {
				Player play = players.get(y);

				if (play.getState() != PlayerState.LOBBY) {
					BufferedImage buffImg = imgCat;

					g.drawImage(buffImg, play.getX() * TILE_DIM, play.getY()
							* TILE_DIM, null);
				}
			}
		}
	}

	/**
	 * This method will update the list of existing Players with a new Player
	 * and do one of the following two things:
	 * 
	 * 1) Loop through the whole list, if you find a player with the same
	 * username, then swap that player objects with this one 2) if you don't
	 * find the Player, then add it to the list of players
	 * 
	 * Then it will repaint the whole component to reflect the changes.
	 * 
	 * @param aPlayer
	 *            The player you want update or add (if a player logs in after
	 *            the game begins).
	 */
	public void updateOrAddPlayer(Player aPlayer) {
		// TODO
		// Loop through the whole list, if you find a player with the same
		// username, then swap that player objects with this one,
		// if you don't find the Player, then add it to the list of players and
		// repaint this component.
		if (aPlayer != null) {
			players.add(aPlayer);
			repaint();
		}
	}

	/**
	 * This method will update the list of existing Players with a new/updated
	 * list of Players.
	 * 
	 * @param players
	 *            The new/updated list of players
	 */
	public void updatePlayers(Vector<Player> players) {
		if (players != null) {
			this.players = players;
			repaint();
		}
	}

	/**
	 * The terrain object might be updated from the server, if it is, then this
	 * method will take care of reflecting those changes.
	 * 
	 * @param aTerrain
	 */
	public void updateTerrain(Terrain aTerrain) {
		// TODO
		// Loop through the list of existing Terrain objects and once you find
		// the one\
		// with the same coordinate, swap it with the new one and then repaint
		if (aTerrain != null) {
			mapData.updateTerrain(aTerrain);
			repaint();
		}

	}
	
	

	/**
	 * This is just a Test Harness for this class. It will never be used by
	 * anyone but developers.
	 * 
	 * @param args
	 */
	public static void main(String[] args) {
		// create game data.
		Vector<Player> players = new Vector<Player>();

		// player data
		players.add(new Player("1", 0, 0));
		players.add(new Player("2", 0, 1));
		players.add(new Player("3", 2, 0));

		MapOne mapData = new MapOne();

		// Array stuff

		// create jframe
		JFrame parentFrame = new JFrame();
		Container container = parentFrame.getContentPane();
		ForagingMap fmap = new ForagingMap(mapData, players);
		container.add(fmap);

		// parentFrame.setSize(TILE_WIDTH * MAP_WIDTH, TILE_WIDTH * MAP_HEIGHT);
		parentFrame.setSize(640, 480);
		parentFrame.setLocationRelativeTo(null);
		parentFrame.addWindowListener(new WindowAdapter() {
			@Override
			public void windowClosing(WindowEvent e) {
				System.exit(0);
			}
		});
		parentFrame.setVisible(true);
		//parentFrame.requestFocusInWindow();
		//parentFrame.setFocusable(true);
	}

}